package com.yeye.web.controller;

import com.yeye.util.R;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricDetail;
import org.flowable.engine.history.HistoricDetailQuery;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Controller
@Slf4j
@RequestMapping(value = "workflow")
public class WorkFlowableController {

  @Autowired
  private TaskService taskService;

  @Autowired
  private RuntimeService runtimeService;

  @Autowired
  private RepositoryService repositoryService;

  @Autowired
  private ProcessEngine processEngine;

  @Autowired
  private HistoryService historyService;


  /**
   * @author yeye
   * @description 列表
   * http://localhost:8080/workflow/list?processId=03311800-0439-11ee-9b57-c67eac0e8706
   */
  @RequestMapping(value = "list")
  @ResponseBody
  public R list( String processId) {
    List<HistoricActivityInstance> activities =
      historyService.createHistoricActivityInstanceQuery()
        .processInstanceId(processId)
        .finished()
        .orderByHistoricActivityInstanceEndTime().asc()
        .list();

    for (HistoricActivityInstance activity : activities) {
      System.out.println(activity.getActivityId() + " took "
        + activity.getDurationInMillis() + " milliseconds");
    }
    return R.ok().put("data",activities);
  }

  /**
   * @author yeye
   * @description 启动部署
   */
  @RequestMapping(value = "deploy")
  @ResponseBody
  public R deploy() {
    RepositoryService repositoryService = processEngine.getRepositoryService();
    Deployment deployment = repositoryService.createDeployment()
      .addClasspathResource("LeaveProcess.bpmn20.xml")
      .deploy();

    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
      .deploymentId(deployment.getId())
      .singleResult();
    System.out.println("Found process definition : " + processDefinition.getName());
    return R.ok();
  }


  /**
   * @author yeye
   * @description 启动流程
   * http://localhost:8080/workflow/startLeaveProcess?staffId=100
   */
  @RequestMapping(value = "startLeaveProcess")
  @ResponseBody
  public R startLeaveProcess(String staffId) {
    HashMap<String, Object> map = new HashMap<>();
    map.put("leaveTask", staffId);
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("Leave", map);
    StringBuilder sb = new StringBuilder();
    sb.append("创建请假流程 processId：" + processInstance.getId());
    List<Task> tasks = taskService.createTaskQuery().taskAssignee(staffId).orderByTaskCreateTime().desc().list();
    for (Task task : tasks) {
      sb.append("任务taskId:" + task.getId());
    }
    return R.ok().put("data", sb.toString());
  }

  /**
   * @param taskId
   * @author yeye
   * @description 批准
   * http://localhost:8080/workflow/applyTask?taskId=97a708af-0438-11ee-9b57-c67eac0e8706
   */
  @RequestMapping(value = "applyTask")
  @ResponseBody
  public R applyTask(String taskId) {
    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (task == null) {
      throw new RuntimeException("流程不存在");
    }
    HashMap<String, Object> map = new HashMap<>();
    map.put("checkResult", "通过");
    taskService.complete(taskId, map);
    return R.ok().put("data", "申请审核通过~");
  }

  /**
   * @param taskId
   * @author yeye
   * @description 驳回
   * http://localhost:8080/workflow/rejectTask?taskId=97a708af-0438-11ee-9b57-c67eac0e8706
   */
  @ResponseBody
  @RequestMapping(value = "rejectTask")
  public R rejectTask(String taskId) {
    HashMap<String, Object> map = new HashMap<>();
    map.put("checkResult", "驳回");
    taskService.complete(taskId, map);
    return R.ok().put("data", "申请审核驳回~");
  }


  /**
   * @author yeye
   * @description 生成流程图
   * http://localhost:8080/workflow/createProcessDiagramPic?processId=42966963-0437-11ee-9b57-c67eac0e8706
   */
  @RequestMapping(value = "createProcessDiagramPic")
  public void createProcessDiagramPic(HttpServletResponse httpServletResponse, String processId) throws Exception {

    ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
    if (pi == null) {
      return;
    }
    Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();

    String InstanceId = task.getProcessInstanceId();
    List<Execution> executions = runtimeService
      .createExecutionQuery()
      .processInstanceId(InstanceId)
      .list();

    List<String> activityIds = new ArrayList<>();
    List<String> flows = new ArrayList<>();
    for (Execution exe : executions) {
      List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
      activityIds.addAll(ids);
    }

    /**
     * 生成流程图
     */
    BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
    ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
    ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
    InputStream in = diagramGenerator
      .generateDiagram(bpmnModel,
        "png",
        activityIds,
        flows,
        engconf.getActivityFontName(),
        engconf.getLabelFontName(),
        engconf.getAnnotationFontName(),
        engconf.getClassLoader(),
        1.0,
        true);


    OutputStream out = null;
    byte[] buf = new byte[1024];
    int legth = 0;
    try {
      out = httpServletResponse.getOutputStream();
      while ((legth = in.read(buf)) != -1) {
        out.write(buf, 0, legth);
      }
    } finally {
      if (in != null) {
        in.close();
      }
      if (out != null) {
        out.close();
      }
    }
  }

}
